/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
 * http://www.gnu.org/licenses/lgpl-3.0.html
 */

#ifndef CBEDITOR_H
#define CBEDITOR_H

#include <wx/hashmap.h>
#include <wx/datetime.h>
#include <wx/fontmap.h>
#include <wx/timer.h>

#include "settings.h"
#include "editorbase.h"
#include "printing_types.h"

extern const wxString g_EditorModified;

/*前置声明*/
/*cbEditorInternalData是编辑器使用的私有数据结构。.*/
struct cbEditorInternalData;
class cbEditor;
class ProjectFile;
class EditorColourSet;
class wxSplitterWindow;
class LoaderBase;
class cbStyledTextCtrl;
class wxScintillaEvent;
class wxBoxSizer;


/*
* 实现功能: 一个文件编辑器的实现
* 这个类表示Code::Blocks中的一个内置编辑器.
* 它包含了关于编辑的所有必要信息.
* 当您想要访问Code::Blocks编辑器时,这就是您想要访问的类.
* 为此,请使用Manager::Get()->GetEditorManager()函数.
* 实际使用的编辑器组件是闪烁体(Scintilla),可以通过成员函数GetControl()访问它。
*/

class DLLIMPORT cbEditor : public EditorBase
{
        DECLARE_EVENT_TABLE()
        friend class EditorManager;

    protected:
        /*
          * cbEditor类构造器参数说明:
          * parent参数: notebook的父窗口 -您应该使用EditorManager::Get()获取
          * filename参数: 打开的文件名.如果文件名是空则创建一个新的空的编辑器
          * theme参数: 要使用的初始颜色集.
          * 注:您不能直接创建cbEditor对象.而是使用EditorManager的方法来完成...
          */
        cbEditor(wxWindow* parent, const wxString& filename, EditorColourSet* theme = nullptr);
        cbEditor(wxWindow* parent, LoaderBase* fileLdr, const wxString& filename, EditorColourSet* theme = nullptr);
        /*cbEditor析构. */
        ~cbEditor();
    public:
        enum SplitType
        {
            /*窗口拆分类型*/
            stNoSplit = 0,
            stHorizontal,
            stVertical
        };

        /* 别用这个.如果你这样做,它会抛出一个异常.*/
        void operator=(cb_unused const cbEditor& rhs){ cbThrow(wxT("无法指派编辑器指针(cbEditor*)!!!")); }

        /*属性*/

        /**返回一个指向底层cbStyledTextCtrl对象的指针(它本身就是Scintilla的wxWindows实现).
          * 如果你想影操纵辑器的实际内容,这就是你想要得到的对象.
          * @备注 如果编辑器被拆分,此函数将返回当前具有键盘焦点的控件.不要保存此指针,因为它以后可能会无效...
          */
        cbStyledTextCtrl* GetControl() const;

        /*返回指向左侧(或顶部)拆分视图cbStyledTextCtrl的指针.此函数始终返回有效指针.*/
        cbStyledTextCtrl* GetLeftSplitViewControl() const { return m_pControl; }

        /*返回指向右侧(或底部)拆分视图cbStyledTextCtrl的指针.如果编辑器未拆分,此函数可能返回NULL.*/
        cbStyledTextCtrl* GetRightSplitViewControl() const { return m_pControl2; }

        /** 返回此编辑器的拆分视图状态. */
        SplitType GetSplitType() const { return m_SplitType; }

        /*如果编辑器正常(OK),即使用文件名参数调用构造了函数并成功打开文件,则返回true.如果它返回false,您应该删除编辑器...*/
        bool IsOK() const { return m_IsOK; }

        /*设置编辑器标题.对于选项卡式界面,它设置相应的选项卡文本,而对于MDI界面,它设置MDI窗口标题...*/
        void SetEditorTitle(const wxString& title);

        /** 编辑器被修改返回真否则假*/
        bool GetModified() const;

        /**使用modified参数设置编辑器的修改状态*/
        void SetModified(bool modified = true);

        /*设置与此编辑器关联的项目文件指针.
          * 属于项目文件的所有编辑器都应具有此集合.
          * 所有其他的都应该返回NULL.
          * 您可以选择保留文件的"modified"标志.
          */
        void SetProjectFile(ProjectFile* project_file,bool preserve_modified = false);

        /*读取与此编辑器关联的项目文件指针.
          * 属于项目文件的所有编辑器都具有此集.
          * 其他全部返回空值.
          */
        ProjectFile* GetProjectFile() const { return m_pProjectFile; }
        /** 使用编辑器的插入符号位置,顶部可见行及其打开状态更新关联的ProjectFile对象.
          * 用于devProject布局信息中,因此每次用户在IDE中打开项目文件时,
          * 它都会以与上次关闭时完全相同的状态打开.
          */
        void UpdateProjectFile();
        /*保存编辑器内容.成功时返回true否则返回false.*/
        bool Save();
        /*将编辑器内容保存在其他文件名下.成功时返回true否则返回false.*/
        bool SaveAs();
        /*在新的cbStyledTextCtrl中保存折叠状态.这将保存整个文档,从而在折叠选项更改之前保存折叠状态*/
        bool SaveFoldState();
        /*通过比较foldBackup和m_pControl修复折叠状态.这是Scintilla错误的临时修正(修正折叠状态)*/
        bool FixFoldState();
         /*折叠所有编辑器折叠(隐藏代码块).*/
        void FoldAll();
         /*展开所有编辑器折叠(显示代码块).*/
        void UnfoldAll();
         /*切换所有编辑器折叠(反转代码块的显示/隐藏状态).*/
        void ToggleAllFolds();
         /*设置折叠式指示器的类型,其中id是以下类型之一:0->箭头,1->圆,2->正方形,3->简单(设置折叠式指示器)*/
        void SetFoldingIndicator(int id);
         /*折叠包含行线的块.如果行是-1,则折叠包含插入符号的块.*/
        void FoldBlockFromLine(int line = -1);
         /*折叠包含行的块.如果行是-1,则折叠包含插入符号的块.*/
        void UnfoldBlockFromLine(int line = -1);
         /*切换包含参数行的块的折叠.如果行是-1,则切换包含插入符号的块的折叠.*/
        void ToggleFoldBlockFromLine(int line = -1);
         /*设置要使用的颜色集.*/
        void SetColourSet(EditorColourSet* theme);
         /*用上这套颜色.*/
        EditorColourSet* GetColourSet() const { return m_pTheme; }
         /*跳到匹配的大括号(如果有).*/
        void GotoMatchingBrace();
         /*突出显示大括号对(其中一个大括号必须在光标下)*/
        void HighlightBraces();
         /*返回指定行(基于0)的缩进(空格).如果line是-1,则使用当前行(在空格中获取行缩进)*/
        int GetLineIndentInSpaces(int line = -1) const;
         /*返回指定行的(基于0的)缩进(空白)字符串.如果line是-1,则使用当前行(获取行缩进字符串)*/
        wxString GetLineIndentString(int line = -1) const;
         /*返回文件的最后修改时间.用于检测编辑器外部的修改.(获取上次修改时间)*/
        wxDateTime GetLastModificationTime() const { return m_LastModified; }
         /*将文件的上次修改时间设置为"现在".用于检测编辑器外部的修改.*/
        void Touch();
         /*从磁盘重新加载文件.成功时返回真,失败时返回假.*/
        bool Reload(bool detectEncoding = true);
        /**
          * 打印文件
          * 参数说明: selectionOnly 应仅打印所选文本吗?
          * 参数说明: pcm 打印时使用的颜色模式
          * 参数说明: line_numbers 打印文件的行号.
          */
        void Print(bool selectionOnly, PrintColourMode pcm, bool line_numbers);
         /*此方法已过时,请改用缩写插件.*/
        void AutoComplete();
        /**
          * 在指定行移动插入符号.
          * 参数说明: line 要将插入符号移动到的行.
          * 参数说明: centerOnScreen 如果为true(默认),则尝试将指定的行置于编辑器的中心.(转到行)
          * */
        void GotoLine(int line, bool centerOnScreen = true);
        /**
          * 在指定行移动插入符号.
          * 参数说明: line      要将插入符号移动到的行(标记所在的位置).
          * 参数说明: tokenName 要突出显示的标记名(字符串)(如果找到)
          * 返回值:  找到编辑器,位置集和标记突出显示?
          * (转到令牌[标识符]位置)
          * */
        bool GotoTokenPosition(int line, const wxString& tokenName);
         /*在指定行添加调试器断点.如果参数line是-1,则使用当前行.(添加断点)*/
        bool AddBreakpoint(int line = -1, bool notifyDebugger = true);
        /*移除指定行上的调试器断点.如果参数line是-1,则使用当前行.(移除断点)*/
        bool RemoveBreakpoint(int line = -1, bool notifyDebugger = true);
        /*在指定行切换调试器断点.如果参数line是-1,则使用当前行.(切换断点)*/
        virtual void ToggleBreakpoint(int line = -1, bool notifyDebugger = true);
        /*参数line是否有调试器断点?如果参数line是-1,则使用当前行.(代码行存在断点)*/
        virtual bool HasBreakpoint(int line) const;
        /*跳转至下一个调试器断点*/
        virtual void GotoNextBreakpoint();
        /*跳转至前一个调试器断点*/
        virtual void GotoPreviousBreakpoint();
         /*刷新断点的所有标记(仅显示当前调试器的标记)(刷新断点标签)*/
        virtual void RefreshBreakpointMarkers();
         /*清除所有书签*/
        virtual void ClearAllBookmarks();
         /*在指定行切换书签.如果参数line是-1,则使用当前行.(切换书签)*/
        virtual void ToggleBookmark(int line = -1);
         /*(代码行存在书签)*/
        virtual bool HasBookmark(int line) const;
        /*(跳转到下一个书签)*/
        virtual void GotoNextBookmark();
         /*(跳转到前一个书签)*/
        virtual void GotoPreviousBookmark();
         /*突出显示调试器接下来将执行的行.(设置调试行)*/
        virtual void SetDebugLine(int line);
         /*将指定的行突出显示为错误.*/
        virtual void SetErrorLine(int line);
          /*拆分编辑器窗口 split参数 拆分的类型(水平或垂直).*/
        void Split(SplitType split);
         /*取消编辑器窗口拆分*/
        void Unsplit();
        /*下面的函数尽管不言自明,但在EditorBase中有文档记录.*/
        void Undo();
        void Redo();
        void ClearHistory();
        void GotoNextChanged();
        void GotoPreviousChanged();
        void SetChangeCollection(bool collectChange);
        void Cut();
        void Copy();
        void Paste();
        bool CanUndo() const;
        bool CanRedo() const;
        bool HasSelection() const;
        bool CanPaste() const;
        bool IsReadOnly() const;
        void SetReadOnly(bool readonly = true);

        bool CanSelectAll() const;
        void SelectAll();

        /*wx2.4.2中的shift-tab错误的解决方法*/
        /*执行当前行/块缩进*/
        void DoIndent();
        /*取消当前行/块缩进*/
        void DoUnIndent();

        /*其他函数(功能)*/

        /*创建上下文子菜单*/
        virtual wxMenu* CreateContextSubMenu(long id);
        /*添加上下文菜单*/
        virtual void AddToContextMenu(wxMenu* popup,ModuleType type,bool pluginsdone);  //pecan 2006/03/22
        /*获取突出显示的语言*/
        HighlightLanguage GetLanguage( ) const { return m_lang; }
        /*设置语法突出显示语言*/
        void SetLanguage( HighlightLanguage lang = HL_AUTO );
        /*获取字体编码*/
        wxFontEncoding GetEncoding( ) const;
        /*获取编码名称*/
        wxString GetEncodingName( ) const;
        /*设置编码名称*/
        void SetEncoding( wxFontEncoding encoding );
        /*获取BOM清单*/
        bool GetUseBom() const;
        /*设置BOM清单*/
        void SetUseBom( bool bom );
        /*设置缩放*/
        void SetZoom(int zoom, bool both = true);
        /*将编辑器默认值应用于任何(可能是外部的)cbStyledTextCtrl.*/
        static void ApplyStyles(cbStyledTextCtrl* control);
        /*执行自动缩进*/
        void AutoIndentDone();
        /*应用与编辑器文件名匹配的样式.应在创建新文件后调用.调用SaveAs做同样的事情.*/
        void SetEditorStyle();
    private:
        /*防止复制构造*/
        cbEditor(cb_unused const cbEditor& rhs);
        /*成员函数*/
        bool LineHasMarker(int marker, int line = -1) const;
        void MarkerToggle(int marker, int line = -1);
        void MarkerNext(int marker);
        void MarkerPrevious(int marker);
        void MarkLine(int marker, int line);
        /*折叠 0=unfold, 1=fold, 2=toggle*/
        void DoFoldAll(int fold);
        /*行块折叠*/
        void DoFoldBlockFromLine(int line, int fold);
        /*行折叠*/
        bool DoFoldLine(int line, int fold);
        void SetMarkerStyle(int marker, int markerType, wxColor fore, wxColor back);
        void UnderlineFoldedLines(bool underline);
        cbStyledTextCtrl* CreateEditor();
        void ConnectEvents(cbStyledTextCtrl* stc);
        void SetEditorStyleBeforeFileOpen();
        void SetEditorStyleAfterFileOpen();
        static void InternalSetEditorStyleBeforeFileOpen(cbStyledTextCtrl* control);
        static void InternalSetEditorStyleAfterFileOpen(cbStyledTextCtrl* control);
        bool Open(bool detectEncoding = true);
        /*与自动代码完成插件相关*/
        void DoAskForCodeCompletion();
        static wxColour GetOptionColour(const wxString& option, const wxColour _default);
        void NotifyPlugins(wxEventType type, int intArg = 0, const wxString& strArg = wxEmptyString, int xArg = 0, int yArg = 0);

        /*事件*/
        void OnMarginClick(wxScintillaEvent& event);
        void OnEditorUpdateUI(wxScintillaEvent& event);
        void OnEditorChange(wxScintillaEvent& event);
        void OnEditorCharAdded(wxScintillaEvent& event);
        void OnEditorDwellStart(wxScintillaEvent& event);
        void OnEditorDwellEnd(wxScintillaEvent& event);
        void OnEditorModified(wxScintillaEvent& event);
        void OnUserListSelection(wxScintillaEvent& event);
        void OnZoom(wxScintillaEvent& event);
        /**通知所有注册的EditorHook函数
         * event参数 指示cbEditor接收的事件
         * 您应该直接或间接地将OnScintillaEvent绑定到每个wxScintillaEvent事件,
         * 有关详细信息,请参见cbEditor::ConnectEvents().
         */
        void OnScintillaEvent(wxScintillaEvent& event);
        void OnClose(wxCloseEvent& event);

        /*所有弹出菜单项的一个事件处理程序*/
        void OnContextMenuEntry(wxCommandEvent& event);
        bool OnBeforeBuildContextMenu(const wxPoint& position, ModuleType type);    //pecan 2006/03/22
        void OnAfterBuildContextMenu(ModuleType type);                              //pecan 2006/03/22
        void DestroySplitView();
        void DoInitializations(const wxString& filename, LoaderBase* fileLdr = nullptr);
        void BreakpointMarkerToggle(int line);

        /*变量*/
        bool m_IsOK;
        wxSplitterWindow* m_pSplitter;
        wxBoxSizer* m_pSizer;
        cbStyledTextCtrl* m_pControl;
        cbStyledTextCtrl* m_pControl2;
        cbStyledTextCtrl* m_foldBackup;
        SplitType m_SplitType;
        bool m_Modified;
        int m_Index;
        wxTimer m_timerWait;
        ProjectFile* m_pProjectFile;
        EditorColourSet* m_pTheme;
        HighlightLanguage m_lang;
        /*检查文件是否在编辑器外部修改*/
        wxDateTime m_LastModified;
        bool m_autoIndentDone;
        /*不要在这里添加任何变量!改为将它们添加到cbEditorInternalData中!允许cbEditorInternalData访问cbEditor 尽量使用(cbEditorInternalData)友元*/
        friend struct cbEditorInternalData;
        cbEditorInternalData* m_pData;
};

#endif // CBEDITOR_H
